package db

import (
	"database/sql"
	"fmt"
	"log"
	"time"

	"dict-server/config"

	"github.com/go-sql-driver/mysql"
)

// 全局数据库连接实例
var DB *sql.DB

// Word 单词数据模型，对应数据库表结构
type Word struct {
	Word  string `json:"word"`  // 单词（主键）
	Trans string `json:"trans"` // 单词释义
}

// Init 初始化数据库连接及表结构
// 负责：创建数据库、连接数据库、配置连接池、初始化表结构
func Init(cfg *config.DatabaseConfig) error {
	// 临时连接MySQL服务器（用于创建数据库）
	tempDB, err := connectWithoutDB(cfg)
	if err != nil {
		return fmt.Errorf("临时连接失败: %w", err)
	}
	defer tempDB.Close()

	// 创建目标数据库（若不存在）
	if err := createDatabase(tempDB, cfg.Name); err != nil {
		return fmt.Errorf("创建数据库失败: %w", err)
	}

	// 连接到目标数据库
	if err := connectWithDB(cfg); err != nil {
		return fmt.Errorf("连接数据库失败: %w", err)
	}

	// 配置连接池参数
	setupConnPool(cfg)

	// 验证数据库连接
	if err := DB.Ping(); err != nil {
		return fmt.Errorf("连接验证失败: %w", err)
	}

	// 创建单词表
	if err := createWordsTable(); err != nil {
		return fmt.Errorf("创建表结构失败: %w", err)
	}

	log.Println("数据库初始化成功")
	return nil
}

// 临时连接
func connectWithoutDB(cfg *config.DatabaseConfig) (*sql.DB, error) {
	mysqlCfg := mysql.Config{
		User:                 cfg.User,
		Passwd:               cfg.Password,
		Net:                  "tcp",
		Addr:                 fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
		ParseTime:            true,
		Loc:                  time.Local,
		AllowNativePasswords: true,
	}

	return sql.Open("mysql", mysqlCfg.FormatDSN())
}

// 连接到指定数据库
func connectWithDB(cfg *config.DatabaseConfig) error {
	mysqlCfg := mysql.Config{
		User:                 cfg.User,
		Passwd:               cfg.Password,
		Net:                  "tcp",
		Addr:                 fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
		DBName:               cfg.Name,
		ParseTime:            true,
		Loc:                  time.Local,
		AllowNativePasswords: true,
	}

	var err error
	DB, err = sql.Open("mysql", mysqlCfg.FormatDSN())
	return err
}

// 创建数据库
func createDatabase(db *sql.DB, dbName string) error {
	_, err := db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", dbName))
	return err
}

// 配置连接池
func setupConnPool(cfg *config.DatabaseConfig) {
	DB.SetMaxOpenConns(cfg.MaxOpenConns)       // 最大打开连接数
	DB.SetMaxIdleConns(cfg.MaxIdleConns)       // 最大空闲连接数
	DB.SetConnMaxLifetime(cfg.ConnMaxLifetime) // 连接最大存活时间
}

// 创建单词表结构
func createWordsTable() error {
	query := `
	CREATE TABLE IF NOT EXISTS words (
		word VARCHAR(100) NOT NULL PRIMARY KEY,
		trans TEXT NOT NULL
	) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
	`
	_, err := DB.Exec(query)
	return err
}

// InsertWords 批量插入单词
// 返回成功插入的条数
func InsertWords(words []Word, batchSize int) (int, error) {
	if len(words) == 0 {
		return 0, nil
	}

	// 计算总批次
	totalInserted := 0
	batchCount := (len(words) + batchSize - 1) / batchSize

	for i := 0; i < batchCount; i++ {
		start, end := i*batchSize, (i+1)*batchSize
		if end > len(words) {
			end = len(words)
		}

		// 插入单批次数据
		inserted, err := insertBatch(words[start:end])
		if err != nil {
			return totalInserted, fmt.Errorf("批次插入失败: %w", err)
		}
		totalInserted += inserted
	}

	return totalInserted, nil
}

// 插入单批次单词
func insertBatch(batch []Word) (int, error) {
	// 构建批量插入SQL
	query := "INSERT IGNORE INTO words (word, trans) VALUES "
	params := make([]interface{}, 0, len(batch)*2)

	for i, word := range batch {
		if i > 0 {
			query += ", "
		}
		query += "(?, ?)"
		params = append(params, word.Word, word.Trans)
	}

	// 执行插入
	result, err := DB.Exec(query, params...)
	if err != nil {
		return 0, err
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return 0, err
	}

	return int(rowsAffected), nil
}

// GetWord 查询单词详情
// 若单词不存在，返回nil
func GetWord(word string) (*Word, error) {
	query := "SELECT word, trans FROM words WHERE word = ?"

	var w Word
	err := DB.QueryRow(query, word).Scan(&w.Word, &w.Trans)
	switch {
	case err == sql.ErrNoRows:
		// 单词不存在
		return nil, nil
	case err != nil:
		return nil, fmt.Errorf("查询失败: %w", err)
	default:
		return &w, nil
	}
}

// CleanWords 清空单词表数据
func CleanWords() (int64, error) {
	result, err := DB.Exec("TRUNCATE TABLE words")
	if err != nil {
		return 0, fmt.Errorf("清空失败: %w", err)
	}
	return result.RowsAffected()
}

// Close 关闭数据库连接
func Close() error {
	if DB != nil {
		return DB.Close()
	}
	return nil
}
